package com.wl.dzt.sys.core.dao.template;

import com.wl.dzt.sys.core.dao.DB;
import com.wl.dzt.sys.core.dao.JDao;
import com.wl.dzt.sys.core.dao.select.Select;
import com.wl.dzt.sys.core.dao.select.term.Term;
import com.wl.dzt.sys.core.dao.template.bean.ManyToMany;
import com.wl.dzt.sys.core.dao.template.bean.TagerInfo;
import com.wl.dzt.sys.util.CollectionUtil;
import com.wl.dzt.sys.util.FieldUtil;
import com.wl.dzt.sys.util.LogicUtil;
import com.wl.dzt.sys.util.clazz.ClassUtil;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wl_code@163.com
 * @version 1.0
 * @date 2018/7/5/005
 * @description 数据操作模板
 * 用于封装常见的数据保存类型
 */
@Component
@Transactional
public class OrmTemplate {

    @Resource
    private JDao dao;

    /**
     * <b>多对多保存</b>
     * <p>
     * 通常用于处理某个数据所对应的多行数据.<br>
     * 如 一个角色所对应的多个模块
     * </p>
     *
     * @param manyToMany
     */
    public void manyToMany(ManyToMany manyToMany) {
        List<Object> list = new ArrayList<>();
        Class<?> clazz = manyToMany.getManyToManyEntityClass(); // 中间表实体类
        Object src = ClassUtil.newInstance(FieldUtil.get(clazz, manyToMany.getSrcField()).getType());// 源表实例
        DB.setId(src, manyToMany.getSrcFieldId());// 为源表设置ID
        // 获取第一个目标
        TagerInfo first = manyToMany.getTagerInfos().get(0);
        if (!LogicUtil.empty(first.getIds())) {
            String ids[] = first.getIds().split(",");
            for (int index = 0; index < ids.length; index++) {
                Object ref = ClassUtil.newInstance(clazz); // 中间表实例
                BeanMap beanMap = BeanMap.create(ref);
                beanMap.put(manyToMany.getSrcField(), src);
                for (int i = 0; i < manyToMany.getTagerInfos().size(); i++) {
                    TagerInfo info = manyToMany.getTagerInfos().get(i);
                    Class<?> tagerClazz = FieldUtil.get(clazz, info.getTagerField()).getType();
                    Object tgr = ClassUtil.newInstance(tagerClazz);// 目标表实例
                    DB.setId(tgr, info.getIds().split(",")[index]);
                    beanMap.put(info.getTagerField(), tgr);
                }
                list.add(ref);
            }
        }

        // 先删除
        List<?> brs = dao.list(Select.create(clazz).where(Term.eq(manyToMany.getSrcField() + ".id", manyToMany.getSrcFieldId())));
        brs.forEach(b -> dao.delete(clazz, BeanMap.create(b).get("id").toString()));
        // 后添加
        list.forEach(rm -> {
            dao.save(rm);
        });
    }

    /**
     * <b>多对多加载</b>
     * <p>
     * 对应多对多保存<br >
     * 源字段名称和源字段值请参考代码规范 <br >
     * 返回需要加载的目标模块字段：id用逗号隔开的字符串<br >
     * </p>
     *
     * @param param
     * @return
     */
    public Map<String, String> getManyToMany(Map<String, String> param) {
        String src = param.get("src"), srcId = param.get("srcId");
        Class<?> clazz = ClassUtil.createClass(param.get("manyToManyEntityClass"));
        param.remove("src");
        param.remove("srcId");
        param.remove("manyToManyEntityClass");
        List<String> keys = new ArrayList<String>(), fields = new ArrayList<String>();
        param.keySet().stream().forEach(key -> {
            keys.add(key);
            fields.add(key + ".id");
        });
        List<?> brs = dao.list(Select.create(clazz).where(Term.eq(src, srcId)).fields(fields.toArray(new String[fields.size()])));
        Map<String, String> result = new HashMap<String, String>();
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        brs.forEach(obj -> {
            keys.forEach(key -> {
                List<String> list = map.get(key);
                if (list == null) {
                    list = new ArrayList<>();
                    map.put(key, list);
                }
                Object tager = FieldUtil.doGetMethod(obj, key);
                list.add(FieldUtil.doGetMethod(tager, "id") + "");
            });
        });
        map.forEach((k, v) -> {
            result.put(k, CollectionUtil.join(v, ","));
        });
        return result;
    }
}
